#include "database.h"
#include <iostream>
#include <cstring>

Database::Database(const std::string& host, const std::string& user,
                   const std::string& password, const std::string& database, int port)
    : host_(host), user_(user), password_(password), database_(database), port_(port), conn_(nullptr) {
}

Database::~Database() {
    disconnect();
}

bool Database::connect() {
    conn_ = mysql_init(nullptr);
    if (!conn_) {
        std::cerr << "mysql_init() failed" << std::endl;
        return false;
    }

    if (!mysql_real_connect(conn_, host_.c_str(), user_.c_str(),
                           password_.c_str(), database_.c_str(), port_, nullptr, 0)) {
        std::cerr << "Connection failed: " << mysql_error(conn_) << std::endl;
        mysql_close(conn_);
        conn_ = nullptr;
        return false;
    }

    // 设置字符集为UTF-8
    if (mysql_set_character_set(conn_, "utf8mb4") != 0) {
        std::cerr << "Setting character set failed: " << mysql_error(conn_) << std::endl;
        return false;
    }

    return true;
}

void Database::disconnect() {
    if (conn_) {
        mysql_close(conn_);
        conn_ = nullptr;
    }
}

bool Database::isConnected() const {
    return conn_ != nullptr;
}

std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)> Database::query(const std::string& sql) {
    if (!isConnected()) {
        return std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>(nullptr, mysql_free_result);
    }

    if (mysql_query(conn_, sql.c_str()) != 0) {
        std::cerr << "Query failed: " << mysql_error(conn_) << std::endl;
        return std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>(nullptr, mysql_free_result);
    }

    MYSQL_RES* result = mysql_store_result(conn_);
    return std::unique_ptr<MYSQL_RES, decltype(&mysql_free_result)>(result, mysql_free_result);
}

bool Database::execute(const std::string& sql) {
    if (!isConnected()) {
        return false;
    }

    if (mysql_query(conn_, sql.c_str()) != 0) {
        std::cerr << "Execute failed: " << mysql_error(conn_) << std::endl;
        return false;
    }

    return true;
}

unsigned long long Database::getLastInsertId() {
    return mysql_insert_id(conn_);
}

std::string Database::escapeString(const std::string& str) {
    if (!isConnected()) {
        return str;
    }

    char* escaped = new char[str.length() * 2 + 1];
    mysql_real_escape_string(conn_, escaped, str.c_str(), str.length());
    std::string result(escaped);
    delete[] escaped;
    return result;
}
